﻿using Digitalmes.Common.Exceptions;
using Digitalmes.Common.Security;

namespace Digitalmes.Common.Behaviours;

/// <summary>
/// MediatR 身份授权验证管道。
/// </summary>
/// <typeparam name="TRequest"></typeparam>
/// <typeparam name="TResponse"></typeparam>
/// <param name="currentUser">当前用户信息，注：（服务未注册服务时会为 null）。</param>
/// <exception cref="UnauthorizedAccessException"></exception>
/// <exception cref="ForbiddenAccessException"></exception>
public sealed class AuthorizationBehaviour<TRequest, TResponse>([MaybeNull] ICurrentUser? currentUser = null) : IPipelineBehavior<TRequest, TResponse>
     where TRequest : notnull
{
    public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
    {
        // 对于有指定授权的命令，必须存在用户信息。
        var authorizeAttrs = request.GetType().GetCustomAttributes<AuthorizeAttribute>();
        if (authorizeAttrs.Any())
        {
            if (currentUser?.UserId is null)
            {
                throw new UnauthorizedAccessException();
            }

            var authorizeRoles = authorizeAttrs.SelectMany(s => s.Roles).ToArray();
            if (authorizeRoles.Length > 0)
            {
                var authorized = currentUser.Roles.Any(u => authorizeRoles.Contains(u));
                // Must be a member of at least one role in roles
                if (!authorized)
                {
                    throw new ForbiddenAccessException();
                }
            }
        }

        return await next();
    }
}
